package com.info.zhiduoduo.common.annotation;

import com.info.zhiduoduo.common.exception.ZddLogFieldNotFoundException;
import com.info.zhiduoduo.common.exception.ZddLogParamenterNotFoundException;
import com.info.zhiduoduo.common.formbean.BaseSimpleFormBean;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * 标记 系统中要记录操作日志时，请求参数中的什么字段是需要用来去查询数据库Entity对象的
 * <p> 配合{@link LogEntity}注解使用。
 *
 * @see ZddLog
 */
@Target({ElementType.PARAMETER})
@Retention(RUNTIME)
@Documented
public @interface LogParameter {

	/**
	 * 指定{@link LogEntity#entity()} Model entity表结构中的column名，用这个字段去查询entity对象。默认为主键"id"
	 * <p> </p>
	 * 支持多个字段名称，表示要通过多个字段去查询一个entity对象。
	 * <p> </p>
	 * 这里设置的fields数量需要与{@link LogParameter#parameters()} 一致。
	 * <p> </p>
	 * 如果设置的字段在{@link LogEntity#entity()} Class中没有找到，在接口执行时会抛出异常{@link ZddLogFieldNotFoundException}。
	 * <p> </p>
	 * 例如：我们要通过手机号查询Maker数据，则这里可以配置成 "phone"，实际会用如下代码去查询：
	 * <pre>
	 *    Maker maker = new Maker().selectOne(Condition.create().eq("phone", parameter));
	 *
	 *    代码中的parameter就是根据{@link LogParameter#parameters()}中配置的参数去查找到的具体请求参数的phone的值。
	 * </pre>
	 *
	 * @see ZddLogFieldNotFoundException
	 */
	String[] fields() default {"id"};

	/**
	 * 指定请求参数对象被@RequestBody标记的{@link BaseSimpleFormBean}或URL请求参数中的哪些字段是用来当作参数值去查询entity对象。默认为"formBean.reqdata",
	 * 表示请求参数对象reqdata为entity的主键id。与{@link LogParameter#fields()}配合使用。
	 * <p> 格式如下： </p>
	 * <p> </p>
	 * 1. @LogParameter(fields={"id", "name"}, parameters={"id", "name"}) 表示参数直接放在接口方法的形式参数列表上，则直接指定形式参数名即可。如下：
	 * <pre>
	 *  Controller接口方法：
	 *  publick SmartResult updateMakerName(int id, String name){
	 *      // 业务逻辑等等
	 *  };
	 * </pre>
	 *
	 * <p> </p>
	 * 2. @LogParameter(fields={"userid"}, parameters={"formbean.reqdata.userid"}) 表示是多个层级的requestBody请求参数，且其中的userid需要作为查询entity
	 * 对象的字段，formbean是接口controller方法的形式参数名称。
	 * <pre>
	 *  Controller接口方法：
	 *  public SmartResult verifyAccount(@RequestBody BaseSimpleFormBean formBean) {
	 * 	    return makerService.verifyAccount(formBean);
	 *  }
	 *  formBean对象：
	 *  {
	 *     "userid": 1,
	 *     "token": "xxx",
	 *     "reqdata": {
	 *         "userid": 1,
	 *         "state": 2
	 *     },
	 *     "page": 0,
	 *     "rows": 0
	 * }
	 * </pre>
	 *
	 * <p> </p>
	 * 3. @LogParameter(fields={"userid"}, parameters={"formbean.reqdata.userids[i]"}) 逗号分隔的字符串特殊请求参数格式，需要拆分成id
	 * 列表，并且表示需要记录多个entity的操作日志，则表示成"formBean.reqdata.userids[i]",
	 * 最后的方括号中的i表示要转成Integer；如果方括号中没有字母"formBean.reqdata.userids[]"，则表示默认转成字符串。
	 * 同理，第1条中的url参数也可以使用这个格式：@LogParameter(fields={"id", "name"}, parameters={"userids[i]", "name"})
	 * <pre>
	 *  Controller接口方法：
	 *  public SmartResult verifyAccount(@RequestBody BaseSimpleFormBean formBean) {
	 * 	    return makerService.verifyAccount(formBean);
	 *  }
	 *  formBean对象：
	 *  {
	 *     "userid": 1,
	 *     "token": "xxx",
	 *     "reqdata": {
	 *         "userids": "101,432,9671",
	 *         "state": 2
	 *     },
	 *     "page": 0,
	 *     "rows": 0
	 * }
	 * </pre>
	 *
	 * <p> </p>
	 * 4. @LogParameter(fields={"userid"}, parameters={"formbean.reqdata.userid"}) 带list的特殊请求参数格式，会自动判断reqdata是否为list
	 * 类型，如果是则表示要记录多个entity的操作日志。
	 * <pre>
	 *  {
	 *     "userid": 1,
	 *     "token": "xxx",
	 *     "reqdata": [
	 *        {
	 *           "userid": 101,
	 * 	         "state": 2
	 *        },
	 *        {
	 *           "userid": 432,
	 * 	         "state": 2
	 *        }
	 *     ],
	 *     "page": 0,
	 *     "rows": 0
	 * }
	 * </pre>
	 *
	 * <p> </p>
	 * 5. 这里设置的parameters数量需要与{@link LogParameter#fields()} 一致。
	 * <p> </p>
	 * 如果设置的字段在请求参数对象或dependOnEntity Class中没有找到，在接口执行时会抛出异常{@link ZddLogParamenterNotFoundException}。
	 *
	 * @see ZddLogParamenterNotFoundException
	 */
	String[] parameters() default {"formBean.reqdata"};
}
